import { Injectable } from '@nestjs/common';
import { PrismaService } from '@admin/common/service/prisma/prisma.service';
import { Response } from 'express';
import { exportTable } from '@admin/common/utils';
import { QuerySysUserDto, CreateSysUserDto, UpdateSysUserDto, resetPasswordDto, UpdateSysUserStatusDto, updateProfileDto } from '../dto/index';
import { Prisma } from '@prismaClient';
import { isNotEmpty } from 'class-validator';
import * as assert from 'assert';
import { AuthService } from '@admin/common/service/auth/auth.service';
import { isArray } from 'lodash';
import Result from '@admin/common/result/Result';
import { redisUtils } from '@admin/common/utils/redisUtils';
import { Constants } from '@admin/common/constant/Constants';
@Injectable()
export class UserService {
  constructor(
    private prisma: PrismaService,
    private authService: AuthService
  ) {}
  /**@description 查询用户所有 */
  async selectUserAll() {
    return this.prisma.sysUser.findMany();
  }
  /**@description 分页查询用户列表 */
  async selectUserList(q: QuerySysUserDto) {
    const queryCondition: Prisma.SysUserWhereInput = {};
    if (isNotEmpty(q['deptId'])) {
      queryCondition.deptId = {
        equals: q.deptId
      };
    }
    if (isNotEmpty(q['userName'])) {
      queryCondition.userName = {
        contains: q.userName
      };
    }
    if (isNotEmpty(q['nickName'])) {
      queryCondition.nickName = {
        contains: q.nickName
      };
    }
    if (isNotEmpty(q['userType'])) {
      queryCondition.userType = {
        equals: q.userType
      };
    }
    if (isNotEmpty(q['email'])) {
      queryCondition.email = {
        contains: q.email
      };
    }
    if (isNotEmpty(q['phonenumber'])) {
      queryCondition.phonenumber = {
        contains: q.phonenumber
      };
    }
    if (isNotEmpty(q['sex'])) {
      queryCondition.sex = {
        equals: q.sex
      };
    }
    if (isNotEmpty(q['avatar'])) {
      queryCondition.avatar = {
        equals: q.avatar
      };
    }
    if (isNotEmpty(q['password'])) {
      queryCondition.password = {
        equals: q.password
      };
    }
    if (isNotEmpty(q['status'])) {
      queryCondition.status = {
        equals: q.status
      };
    }
    if (isNotEmpty(q['loginIp'])) {
      queryCondition.loginIp = {
        equals: q.loginIp
      };
    }
    if (isNotEmpty(q.params.beginLoginDate) && isNotEmpty(q.params.endLoginDate)) {
      queryCondition.loginDate = {
        lte: q.params.endLoginDate,
        gte: q.params.beginLoginDate
      };
    }
    if (isNotEmpty(q.params.beginCreateTime) && isNotEmpty(q.params.endCreateTime)) {
      queryCondition.createTime = {
        lte: q.params.endCreateTime,
        gte: q.params.beginCreateTime
      };
    }
    if (isNotEmpty(q.params.beginUpdateTime) && isNotEmpty(q.params.endUpdateTime)) {
      queryCondition.updateTime = {
        lte: q.params.endUpdateTime,
        gte: q.params.beginUpdateTime
      };
    }
    return {
      rows: await this.prisma.sysUser.findMany({
        skip: (q.pageNum - 1) * q.pageSize,
        take: q.pageSize,
        where: queryCondition,
        include: {
          dept: true
        }
      }),
      total: await this.prisma.sysUser.count({
        where: queryCondition
      })
    };
  }
  /**@description 查询用户详情 */
  async selectUserByUserId(userId: number) {
    return this.prisma.sysUser.findUnique({
      where: {
        userId
      },
      include: {
        roles: true,
        posts: true
      }
    });
  }
  /**@description 新增用户 */
  async addUser(sysUser: CreateSysUserDto) {
    const { roleIds, postIds, ...user } = sysUser;
    sysUser.password = this.authService.encrypt(sysUser.password);
    //删除掉空值
    for (const key in sysUser) {
      !isNotEmpty(sysUser[key]) && delete sysUser[key];
    }
    return this.prisma.$transaction(async db => {
      //更新用户信息
      const addUser = await db.sysUser.create({
        data: user
      });
      const { userId } = addUser;
      //添加用户的部门和角色
      if (isArray(roleIds) && roleIds.length) {
        await db.sysUserRole.createMany({
          data: roleIds.map(v => ({ userId, roleId: v }))
        });
      }
      if (isArray(postIds) && postIds.length) {
        await db.sysUserPost.createMany({
          data: postIds.map(v => ({
            userId,
            postId: v
          }))
        });
      }
      return addUser;
    });
  }
  /**@description 修改用户 */
  async updateUser(sysUser: UpdateSysUserDto) {
    const { roleIds, postIds, ...user } = sysUser;
    //删除掉空值
    for (const key in sysUser) {
      !isNotEmpty(sysUser[key]) && delete sysUser[key];
    }
    await this.prisma.$transaction(async db => {
      //删除用户的部门和角色
      {
        await db.sysUserPost.deleteMany({
          where: {
            userId: sysUser.userId
          }
        });
        await db.sysUserRole.deleteMany({
          where: {
            userId: sysUser.userId
          }
        });
      }
      //添加用户的部门和角色
      if (isArray(roleIds) && roleIds.length) {
        await db.sysUserRole.createMany({
          data: roleIds.map(v => ({
            userId: sysUser.userId,
            roleId: v
          }))
        });
      }
      if (isArray(postIds) && postIds.length) {
        await db.sysUserPost.createMany({
          data: postIds.map(v => ({
            userId: sysUser.userId,
            postId: v
          }))
        });
      }
      //更新用户信息
      return await db.sysUser.update({
        where: {
          userId: sysUser.userId
        },
        data: user
      });
    });
    //如果为禁用状态，我们把用户的token删除，禁用账户！
    if (sysUser.status === '0') {
      await redisUtils.del(Constants.LOGIN_TOKEN_KEY + sysUser.userId);
    }
    return Result.ok();
  }

  /**@description 修改用户密码 */
  async resetPassword(sysUser: resetPasswordDto) {
    sysUser.password = this.authService.encrypt(sysUser.password);
    //删除掉空值
    const res = await this.prisma.sysUser.update({
      where: {
        userId: sysUser.userId
      },
      data: {
        password: sysUser.password
      }
    });
    await redisUtils.del(Constants.LOGIN_TOKEN_KEY + sysUser.userId);
    return res;
  }
  /**@description 修改用户状态 */
  async updateStatus(sysUser: UpdateSysUserStatusDto) {
    const res = await this.prisma.sysUser.update({
      where: {
        userId: sysUser.userId
      },
      data: {
        status: sysUser.status
      }
    });
    //如果为禁用状态，我们把用户的token删除，禁用账户！
    if (sysUser.status === '0') {
      await redisUtils.del(Constants.LOGIN_TOKEN_KEY + sysUser.userId);
    }
    return res;
  }

  /**@description 批量删除用户 */
  async deleteUserByUserIds(userIds: number[]) {
    return this.prisma.$transaction(async db => {
      await db.sysUserPost.deleteMany({
        where: {
          userId: {
            in: userIds
          }
        }
      });
      await db.sysUserRole.deleteMany({
        where: {
          userId: {
            in: userIds
          }
        }
      });
      const res = await db.sysUser.deleteMany({
        where: {
          userId: {
            in: userIds
          }
        }
      });
      //清空用户的登录token
      for (const id of userIds) {
        await redisUtils.del(Constants.LOGIN_TOKEN_KEY + id);
      }
      return res;
    });
  }
  /**@description 单个删除用户 */
  async deleteUserByUserId(userId: number) {
    return this.prisma.$transaction(async db => {
      await db.sysUserPost.deleteMany({
        where: {
          userId
        }
      });
      await db.sysUserRole.deleteMany({
        where: {
          userId
        }
      });
      const res = await db.sysUser.delete({
        where: {
          userId
        }
      });
      await redisUtils.del(Constants.LOGIN_TOKEN_KEY + userId);
      return res;
    });
  }
  /**@description 导出用户所有数据为xlsx */
  async exportUser(res: Response) {
    const title = [
      '用户ID',
      '部门ID',
      '用户账号',
      '用户昵称',
      '用户类型（00系统用户）',
      '用户邮箱',
      '手机号码',
      '用户性别（0男 1女 2未知）',
      '头像地址',
      '密码',
      '帐号状态（0停用,1正常 ）',
      '删除标志（0删除，1可用）',
      '最后登录IP',
      '最后登录时间',
      '创建者',
      '创建时间',
      '更新者',
      '更新时间',
      '备注'
    ];
    const data = (await this.selectUserAll()).map(v => Object.values(v));
    data.unshift(title);
    exportTable(data, res);
  }

  /**
   * @description 查询授权角色
   */
  async getAuthRole(userId: number) {
    const user = await this.prisma.sysUser.findUnique({
      where: {
        userId
      },
      include: {
        dept: true,
        roles: {
          include: {
            role: true
          }
        }
      }
    });
    return {
      ...user,
      roles: user.roles.map(v => v.role)
    };
  }

  /**
   * @description 保存授权角色
   */
  async updateAuthRole(userId: number, roleIds: number[]) {
    await this.prisma.$transaction(async db => {
      await db.sysUserRole.deleteMany({
        where: {
          userId
        }
      });
      await db.sysUserRole.createMany({
        data: roleIds.map(roleId => ({
          userId,
          roleId
        }))
      });
    });
    return this.authService.refreshUserInfo(userId);
  }

  /**
   * @description 查询用户个人信息
   */
  async getUserProfile(userId) {
    const user = await this.prisma.sysUser.findUnique({
      where: {
        userId
      },
      include: {
        dept: true,
        posts: {
          include: {
            post: true
          }
        },
        roles: {
          include: {
            role: true
          }
        }
      }
    });
    return {
      ...user,
      roleGroup: user.roles.map(v => v.role.roleName).join(','),
      postGroup: user.posts.map(v => v.post.postName).join(',')
    };
  }

  /**
   * @description 修改用户个人信息
   */
  async updateUserProfile(userId: number, user: updateProfileDto) {
    await this.prisma.sysUser.update({
      where: {
        userId
      },
      data: user
    });
    return this.authService.refreshUserInfo(userId);
  }

  /** 修改头像 */
  async updateAvatar(userId: number, avatar: string) {
    await this.prisma.sysUser.update({
      where: {
        userId
      },
      data: {
        avatar
      }
    });
    return this.authService.refreshUserInfo(userId);
  }

  /** 修改密码 */
  async updateUserPwd(userId: number, oldPassword: string, newPassword: string) {
    assert(isNotEmpty(oldPassword) && isNotEmpty(newPassword), '请检查参数！');
    assert(oldPassword.length > 5 && newPassword.length > 5, '请检查参数！');
    const user = await this.prisma.sysUser.findUnique({
      where: {
        userId
      }
    });
    assert(this.authService.encrypt(oldPassword) === user.password, '验证失败：旧密码不正确！');
    const res = await this.prisma.sysUser.update({
      where: {
        userId
      },
      data: {
        password: this.authService.encrypt(newPassword)
      }
    });
    await redisUtils.del(Constants.LOGIN_TOKEN_KEY + userId);
    return res;
  }
}
